﻿
function Diagram(domEl) {
    this._domEl = domEl;
    //解决鼠标事件中this作用域的标识
    this._domEl.tag = this;

    //所有对象的集合
    this._elementList = [];
    //点击选中的元素
    this._selectedElement = null;
    // 选中元素之后，选择位于元素中的偏移坐标
    this._selectedOffset = null;

    //添加所有的元素(node和line)到集合
    this.addElement = function (el) {
        //添加元素到集合
        this._elementList.push(el);
        //append到svg，真正的渲染
        this._domEl.appendChild(el.getDomEl());
        //自己根据Position更新UI
        el.updateLayout();
    }

    //click event
    this._domEl.addEventListener("click", function (e) {
        //alert(e.target.tagName);
    }, false);

    //所有对象的鼠标事件操作
    this._domEl.onmousedown = function (e) {
        //获取当前类的this
        var diagram = this.tag;
        //鼠标当前位置x,y
        var mousePos = { x: e.clientX, y: e.clientY };
        //从最下面往外层循环，svg添加元素是按照顺序来的，获取最上面的点击元素
        for (var i = diagram._elementList.length - 1; i >= 0; i--) {
            //diagram._elementList里面还有线条，线条是没有hitTest方法的，这里判断一下
            if (diagram._elementList[i].hitTest != undefined) {
                //获取当前点击对象的偏移值以及是否被选中的标识
                var hitResult = diagram._elementList[i].hitTest(mousePos);
                //如果选中
                if (hitResult.isHit) {
                    //当前选中的对象赋值
                    diagram._selectedElement = diagram._elementList[i];
                    //get偏移值
                    diagram._selectedOffset = { x: hitResult.offsetX, y: hitResult.offsetY };
                    break;
                }
            }
        }
    }
    this._domEl.onmousemove = function (e) {
        //获取当前类的this
        var diagram = this.tag;
        //判断是否有选中的对象
        if (diagram._selectedElement != null) {
            //计算鼠标的偏移值
            var mousePos = { x: e.clientX + diagram._selectedOffset.x, y: e.clientY + diagram._selectedOffset.y };
            //重新设置绝对坐标,坐标转换成this._position
            diagram._selectedElement.setActualPosition(mousePos);
            //更新布局.集成自Node父类
            diagram._selectedElement.updateLayout();
        }
    }
    this._domEl.onmouseup = function () {
        var diagram = this.tag;
        diagram._selectedElement = null;
    }
}

function Element() {
    this.updateLayout = function () { }
    this.getDomEl = function () { }
    this.getPosition = function () { };
    this.getSize = function () { };
    this.setPosition = function (pos) { };
    this.setSize = function (size) { };
    this.logFlag = true;
}

function Node(domEl, position, size) {
    this._domEl = domEl;
    Element.apply(this, []);

    this._position = position;
    this._size = size;
    this._parent = null;

    this.getDomEl = function () {
        return this._domEl;
    }

    this._linkList = new Array();

    this.addLink = function (link) {
        this._linkList.push(link);
    }

    this.getLinkPos = function () {
        return [];
    }

    this.setPosition = function (pos) {
        this._position = pos;
    }

    this.setSize = function (size) {
        this._size = size;
    }

    this.getSize = function () {
        return this._size;
    }

    this.updateLayout = function () {
        this.onUpdateLayout(this.logFlag);
        for (var i = 0; i < this._linkList.length; i++) {
            this._linkList[i].updateLayout();
        }
    };

    this.onUpdateLayout = function () { };
    this.getCenterPos = function () { };

    this.hitTest = function (pos) { };

    this.getActualPosition = function () {
        var pos = { x: this._position.x, y: this._position.y };
        var parent = this._parent;
        while (parent != null) {
            pos.x += parent._position.x;
            pos.y += parent._position.y;
            parent = parent._parent;
        }
        return pos;
    }

    this.setActualPosition = function (actualPos) {
        var parent = this._parent;
        if (parent == null) {
            this._position = actualPos;
        }
        else {
            var pactual = this._parent.getActualPosition();
            if (actualPos.x >= pactual.x
                && actualPos.x + this._size.w <= pactual.x + this._parent.getSize().w
                && actualPos.y >= pactual.y
                && actualPos.y + this._size.h <= pactual.y + this._parent.getSize().h) {
                var pos = { x: actualPos.x, y: actualPos.y };
                while (parent != null) {
                    pos.x -= parent._position.x;
                    pos.y -= parent._position.y;
                    parent = parent._parent;
                }

                this._position.x = pos.x;
                this._position.y = pos.y;
            }
        }
    }
}